package webmarket.jpacontrollers;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Level;

import webmarket.common.CommonMethods;
import webmarket.common.MarkerController;
import webmarket.common.MarkerController.MarkerTypes;
import webmarket.model.User;

public class UserJpaController extends JpaControllerBase<User> {
	/**
	 * 
	 */
	private static final long serialVersionUID = -309733597719437493L;

	public UserJpaController() {
		super(User.class);
	}

	public User getCurrent() {
		String currentUserName = CommonMethods.getCurrentUserName();
		return getByUsername(currentUserName);
	}

	public User getByUsername(String username) {
		EntityManager em = getEntityManager();
		User userEntity = null;
		try {
			CriteriaBuilder cb = em.getCriteriaBuilder();
			CriteriaQuery<User> cq = em.getCriteriaBuilder().createQuery(User.class);
			cq.select(cq.from(User.class));
			EntityType<User> user = em.getMetamodel().entity(User.class);
			Root<User> root = cq.from(user);
			cq.select(root);
			Expression<String> usernameexp = root.get(user.getDeclaredSingularAttribute("username", String.class));
			cq.where(cb.equal(usernameexp, username));
			TypedQuery<User> q = em.createQuery(cq);
			userEntity = q.getSingleResult();
		} catch (NoResultException e) {
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		return userEntity;
	}

	public boolean userExists(String username) {
		EntityManager em = getEntityManager();
		boolean exists = false;
		try {
			CriteriaBuilder cb = em.getCriteriaBuilder();
			CriteriaQuery<User> cq = em.getCriteriaBuilder().createQuery(User.class);
			cq.select(cq.from(User.class));
			EntityType<User> user = em.getMetamodel().entity(User.class);
			Root<User> root = cq.from(user);
			cq.select(root);
			Expression<String> usernameexp = root.get(user.getDeclaredSingularAttribute("username", String.class));
			cq.where(cb.equal(usernameexp, username));
			TypedQuery<User> q = em.createQuery(cq);
			//getSingleResult() calls getResultList() internally -> no performance loss, easier
			exists = !q.getResultList().isEmpty();
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		return exists;
	}

	public List<User> getUsers(String userName, String sortCol, String sortDir, int limit, int offset) {
		EntityManager em = getEntityManager();
		List<User> results;
		try {
			CriteriaBuilder cb = em.getCriteriaBuilder();
			CriteriaQuery<User> cq = em.getCriteriaBuilder().createQuery(User.class);
			cq.select(cq.from(User.class));
			EntityType<User> user = em.getMetamodel().entity(User.class);
			Root<User> root = cq.from(user);
			cq.select(root);
			if (!StringUtils.isBlank(userName)) {
				Expression<String> usernameexp = root.get(user.getDeclaredSingularAttribute("username", String.class));
				cq.where(PredicateBuilder.createLikePredicate(cb, usernameexp, userName));
			}
			if (StringUtils.isBlank(sortCol)) {
				sortCol = "username";
			}
			Order order = super.getOrder(sortCol, sortDir.equals("desc"), em, root);
			cq.orderBy(order);

			TypedQuery<User> q = em.createQuery(cq);

			q.setMaxResults(limit);
			q.setFirstResult(offset);

			results = q.getResultList();

		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		return results;
	}

	public int getCount(String userName) {
		int count;
		EntityManager em = getEntityManager();
		try {
			CriteriaBuilder cb = em.getCriteriaBuilder();
			CriteriaQuery<Long> cq = em.getCriteriaBuilder().createQuery(Long.class);
			EntityType<User> user = em.getMetamodel().entity(User.class);
			Root<User> root = cq.from(user);
			Expression<String> usernameexp = root.get(user.getDeclaredSingularAttribute("username", String.class));
			cq.where(PredicateBuilder.createLikePredicate(cb, usernameexp, userName));
			count = super.getCount(PredicateBuilder.createLikePredicate(cb, usernameexp, userName), em, cq, root);
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		return count;
	}

	public boolean setActive(int id, boolean active) {
		EntityManager em = getEntityManager();
		try {
			em.getTransaction().begin();
			User user = em.find(User.class, id);
			user.setActive(active);
			em.merge(user);
			em.getTransaction().commit();
			logger.debug("User active edited: " + id + ":" + active);
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		return true;
	}

	public void addMoney(int userId, int money) {
		logger.entry(userId,money);
		EntityManager em = getEntityManager();
		try {
			em.getTransaction().begin();
			User user = em.find(User.class, userId);
			user.setMoney(user.getMoney()+money);
			em.merge(user);
			em.getTransaction().commit();
		} catch (Throwable e) {
			logger.catching(Level.TRACE, e);
			throw e;
		} finally {
			em.close();
		}
		logger.exit();
	}
}
